package com.ruoyi.common.translate;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.ruoyi.common.annotation.IdToName;
import com.ruoyi.common.translate.constant.Translate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

/**
 * 翻译映射服务
 * WARNING: 不要随便改名字， 对应 AjaxResult -> getTransLateNameService
 */
@Service
public class TranslateNameService {

    // 一级缓存：本地缓存
    private final Cache<CacheKey, String> localCache;

    // 批量查询队列
    private final Map<String, BatchQueryContext> batchContexts = new ConcurrentHashMap<>();
    private final ScheduledExecutorService batchExecutor = Executors.newScheduledThreadPool(2);

    // 统计信息
    private final AtomicLong cacheHitCount = new AtomicLong();
    private final AtomicLong cacheMissCount = new AtomicLong();
    private final AtomicLong batchQueryCount = new AtomicLong();

    // 名称提供者映射
    private final Map<String, NameProvider> nameProviderMap = new ConcurrentHashMap<>();

    @Autowired
    private ApplicationContext applicationContext;

    public TranslateNameService() {
        // 初始化本地缓存（最大10000条，过期时间1小时）
        this.localCache = Caffeine.newBuilder()
                .maximumSize(10000)
                .expireAfterWrite(1, TimeUnit.HOURS)
                .build();

        // 启动批量处理任务
        startBatchProcessor();
    }

    /**
     * 初始化名称提供者
     */
    @Autowired
    public void initNameProviders() {
        // 获取所有 NameProvider 的实现类
        Map<String, NameProvider> providers = applicationContext.getBeansOfType(NameProvider.class);
        for (NameProvider provider : providers.values()) {
            nameProviderMap.put(provider.getType(), provider);
        }
    }

    /**
     * 处理单个对象（同步）
     */
    public void process(Object obj) {
        if (obj == null) return;

        List<MappingTask> tasks = collectMappingTasks(obj);
        if (!tasks.isEmpty()) {
            executeMappingTasks(tasks, false);
        }
    }

    /**
     * 批量处理列表（同步）
     */
    public void processList(List<?> list) {
        if (list == null || list.isEmpty()) return;

        List<MappingTask> allTasks = new ArrayList<>();
        for (Object obj : list) {
            allTasks.addAll(collectMappingTasks(obj));
        }

        if (!allTasks.isEmpty()) {
            executeMappingTasks(allTasks, true);
        }
    }

    /**
     * 异步处理
     */
    @Async
    public CompletableFuture<Void> processAsync(Object obj) {
        return CompletableFuture.runAsync(() -> process(obj));
    }

    @Async
    public CompletableFuture<Void> processListAsync(List<?> list) {
        return CompletableFuture.runAsync(() -> processList(list));
    }

    /**
     * 收集映射任务
     */
    private List<MappingTask> collectMappingTasks(Object obj) {
        List<MappingTask> tasks = new ArrayList<>();
        Class<?> clazz = obj.getClass();

        for (Field field : clazz.getDeclaredFields()) {
            IdToName annotation = field.getAnnotation(IdToName.class);
            if (annotation != null) {
                try {
                    field.setAccessible(true);
                    Object idValue = field.get(obj);
                    if (idValue != null) {
//                        NameProvider nameProvider = nameProviderMap.get(annotation.type());
                        String baseKey = ""; //nameProvider.baseKey;

                        tasks.add(new MappingTask(obj, field, annotation, baseKey + idValue));
                    }
                } catch (Exception e) {
                    // 忽略
                }
            }
        }

        return tasks;
    }

    /**
     * 执行映射任务
     */
    private void executeMappingTasks(List<MappingTask> tasks, boolean isBatch) {
        // 按类型分组
        Map<String, List<MappingTask>> tasksByType = new HashMap<>();
        for (MappingTask task : tasks) {
            tasksByType.computeIfAbsent(task.annotation.type(), k -> new ArrayList<>()).add(task);
        }

        // 按类型批量处理
        for (Map.Entry<String, List<MappingTask>> entry : tasksByType.entrySet()) {
            String type = entry.getKey();
            List<MappingTask> typeTasks = entry.getValue();

            if (isBatch && typeTasks.size() > 1) {
                // 批量查询
                batchQueryAndMap(type, typeTasks);
            } else {
                // 单个查询
                for (MappingTask task : typeTasks) {
                    singleQueryAndMap(task);
                }
            }
        }
    }

    /**
     * 单个查询并映射
     */
    private void singleQueryAndMap(MappingTask task) {
        try {
            String name = getNameFromCacheOrProvider(task.annotation.type(), task.idValue);
            if (name != null) {
                setTargetField(task.obj, task.field, name, task.annotation);
            }
        } catch (Exception e) {
            // 忽略
        }
    }

    /**
     * 批量查询并映射
     */
    private void batchQueryAndMap(String type, List<MappingTask> tasks) {
        // 收集需要查询的ID
        Set<String> queryIds = new HashSet<>();
        Map<String, List<MappingTask>> idToTasks = new HashMap<>();

        for (MappingTask task : tasks) {
            String id = task.idValue;
            queryIds.add(id);
            idToTasks.computeIfAbsent(id, k -> new ArrayList<>()).add(task);
        }

        // 批量查询
        Map<String, String> nameMap = batchGetNames(type, new ArrayList<>(queryIds));
        batchQueryCount.incrementAndGet();

        // 设置结果
        for (Map.Entry<String, String> entry : nameMap.entrySet()) {
            List<MappingTask> relatedTasks = idToTasks.get(entry.getKey());
            if (relatedTasks != null) {
                for (MappingTask task : relatedTasks) {
                    try {
                        setTargetField(task.obj, task.field, entry.getValue(), task.annotation);
                    } catch (Exception e) {
                        // 忽略
                    }
                }
            }
        }
    }

    /**
     * 从缓存或提供者获取名称
     */
    private String getNameFromCacheOrProvider(String type, String id) {
        CacheKey cacheKey = new CacheKey(type, id);

        // 尝试从本地缓存获取
        String cachedName = localCache.getIfPresent(cacheKey);
        if (cachedName != null) {
            cacheHitCount.incrementAndGet();
            return cachedName;
        }

        cacheMissCount.incrementAndGet();

        // 从提供者获取
        NameProvider provider = nameProviderMap.get(type);
        if (provider != null) {
            String name = provider.fetchNameByKey(id);
            if (name != null) {
                // 放入缓存
                localCache.put(cacheKey, name);
                return name;
            }
        }

        return null;
    }

    /**
     * 批量获取名称
     */
    private Map<String, String> batchGetNames(String type, List<String> ids) {
        // 先尝试从缓存获取
        Map<String, String> result = new HashMap<>();
        List<String> uncachedIds = new ArrayList<>();

        for (String id : ids) {
            CacheKey cacheKey = new CacheKey(type, id);
            String cachedName = localCache.getIfPresent(cacheKey);
            if (cachedName != null) {
                result.put(id, cachedName);
                cacheHitCount.incrementAndGet();
            } else {
                uncachedIds.add(id);
                cacheMissCount.incrementAndGet();
            }
        }

        // 批量查询未缓存的ID
        if (!uncachedIds.isEmpty()) {
            NameProvider provider = nameProviderMap.get(type);
            if (provider != null) {
//                List<String> realIds = uncachedIds.stream()
//                        .map(x -> x.replace(Translate.NAME + ":" + type + ":", ""))
//                        .collect(Collectors.toList());
                Map<String, String> queriedNames = provider.fetchNamesByKeys(uncachedIds);
                result.putAll(queriedNames);

                // 批量放入缓存
                for (Map.Entry<String, String> entry : queriedNames.entrySet()) {
                    localCache.put(new CacheKey(type, entry.getKey()), entry.getValue());
                }
            }
        }

        return result;
    }

    /**
     * 设置目标字段
     */
    private void setTargetField(Object obj, Field field, String name, IdToName annotation)
            throws Exception {
        String targetFieldName = annotation.nameField();
        if (targetFieldName.isEmpty()) {
            targetFieldName = field.getName() + "Name";
        }

        Field targetField = obj.getClass().getDeclaredField(targetFieldName);
        targetField.setAccessible(true);
        targetField.set(obj, name);
    }

    /**
     * 启动批量处理器
     */
    private void startBatchProcessor() {
        batchExecutor.scheduleAtFixedRate(this::processBatchQueue, 10, 10, TimeUnit.MILLISECONDS);
    }

    /**
     * 处理批量队列
     */
    private void processBatchQueue() {
        // 可以在这里实现延迟批量处理逻辑
        // 当前版本暂时不需要复杂实现
    }

    /**
     * 预加载常用数据
     */
    public void preload(String type, List<String> ids) {
        batchGetNames(type, ids);
    }

    /**
     * 获取统计信息
     */
    public Map<String, Object> getStats() {
        Map<String, Object> stats = new HashMap<>();
        long hitCount = cacheHitCount.get();
        long missCount = cacheMissCount.get();
        long total = hitCount + missCount;

        stats.put("cacheHitCount", hitCount);
        stats.put("cacheMissCount", missCount);
        stats.put("batchQueryCount", batchQueryCount.get());
        stats.put("cacheHitRate", total > 0 ? (double) hitCount / total : 0);
        stats.put("localCacheSize", localCache.estimatedSize());
        stats.put("nameProviderTypes", nameProviderMap.keySet());
        return stats;
    }

    /**
     * 清除缓存
     */
    public void clearCache() {
        localCache.invalidateAll();
    }

    public void clearCache(String type) {
        // 实现按类型清除缓存
        localCache.asMap().keySet().removeIf(key -> key.type.equals(type));
    }

    /**
     * 获取支持的类型
     */
    public Set<String> getSupportedTypes() {
        return nameProviderMap.keySet();
    }

    // 内部类
    private static class MappingTask {
        final Object obj;
        final Field field;
        final IdToName annotation;
        final String idValue;
//        final String keyName;


        MappingTask(Object obj, Field field, IdToName annotation, String idValue) {
            this.obj = obj;
            this.field = field;
            this.annotation = annotation;
//            this.idValue = idValue;
            this.idValue = Translate.NAME+":"+ annotation.type() + ":" + idValue;
        }


    }

    private static class CacheKey {
        final String type;
        final Object id;

        CacheKey(String type, Object id) {
            this.type = type;
            this.id = id;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            CacheKey cacheKey = (CacheKey) o;
            return Objects.equals(type, cacheKey.type) && Objects.equals(id, cacheKey.id);
        }

        @Override
        public int hashCode() {
            return Objects.hash(type, id);
        }
    }

    private static class BatchQueryContext {
        // 批量查询上下文实现
        boolean shouldFlush() {
            return false;
        }
    }
}